package org.brownhouse.rss;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.brownhouse.rss.torrent.Torrent;

import java.io.*;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;

/**
 * Given a list of torrents and a destination directory, this downloader
 * will grab the selected torrents and only download the ones not already
 * in the destination directory.
 */
public class UniqueTorrentDownloader implements TorrentDownloader {
    private static final Logger log = Logger.getLogger(UniqueTorrentDownloader.class);
    private static final String FILENAME_HEADER = "filename=\"";
    private final Set<Torrent> torrents;
    private final File destDirectory;

    public UniqueTorrentDownloader(Set<Torrent> torrents, File destDirectory) {

        this.torrents = torrents;
        if (destDirectory == null || !destDirectory.isDirectory()) {
            throw new IllegalArgumentException("Invalid destination directory '" + destDirectory + "'");
        }
        this.destDirectory = destDirectory;
    }

    public void downloadTorrents() {
        final Collection collection = FileUtils.listFiles(destDirectory, new String[]{"*.torrent"}, true);

        HttpClient client = new HttpClient();

        for (Iterator<Torrent> iterator = torrents.iterator(); iterator.hasNext();) {
            Torrent torrent = iterator.next();
            GetMethod getMethod = new GetMethod(torrent.getTorrentUrl().toString());
            InputStream in = null;
            try {
                int status = client.executeMethod(getMethod);
                in = getMethod.getResponseBodyAsStream();
                File out = new File(destDirectory + File.separator + getFileName(getMethod, torrent));
                if (!out.exists()) {
                    BufferedOutputStream outStream = new BufferedOutputStream(new FileOutputStream(out));
                    byte[] buffer = new byte[32 * 1024];
                    int bytesRead = 0;
                    while ((bytesRead = in.read(buffer)) != -1)
                    {
                        outStream.write(buffer, 0, bytesRead);
                    }

                    outStream.flush();
                    outStream.close();
                    in.close();
                }
            } catch (IOException e) {
                log.error("Error downloading torrent '" + torrent.getName() + "' from url '" + torrent.getTorrentUrl() + "'.", e);
            }
            finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        log.error("Error closing file stream!", e);
                    }
                }
                getMethod.releaseConnection();
            }

        }
    }

    private String getFileName(GetMethod getMethod, Torrent torrent) {
        String ret;
        //Should be something like inline; filename="Cops.S20E24.HDTV.XviD-STFU.[eztv] [mininova].torrent"
        String contentDisposition = getMethod.getResponseHeader("Content-Disposition").getValue();
        if (contentDisposition.contains(FILENAME_HEADER)) {
            int startIndex = contentDisposition.indexOf(FILENAME_HEADER) + FILENAME_HEADER.length();
            int endIndex = contentDisposition.lastIndexOf("\"");
            ret = contentDisposition.substring(startIndex, endIndex);
        } else {
            ret = torrent.getName() + ".torrent";
        }
        return ret;
    }
}
